﻿using Nop.Core.Caching;
using Nop.Core.Domain.Orders;
using Nop.Core.Domain.Shipping;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Nop.Services.Directory;

namespace Nop.Services.Shipping
{
    public class ShipingDayService : IShipingDayService
    {
        private readonly IHolidayService _holidayService;
        private readonly IZipPostalCodeService _zipPostalCodeService;

        public ShipingDayService(IHolidayService holidayService,
           IZipPostalCodeService zipPostalCodeService)
        {
            this._holidayService = holidayService;
            this._zipPostalCodeService = zipPostalCodeService;
        }

        /// <summary>
        /// 获取有效的ShipmentTimeSpan
        /// </summary>
        /// <param name="orderType"></param>
        /// <param name="addressType"></param>
        /// <param name="sshipmentTimeSpans"></param>
        /// <param name="zipPostalCode">zipPostalCode</param>
        /// <returns></returns>
        public IList<ShippingTimeWindowEx> GetValidateShipmentTimeSpan(int orderType, int addressType, string zipPostalCode, IList<ShippingTimeWindow> sshipmentTimeSpans)
        {
            var shipmentTimeSpans = ShippingTimeWindowEx.ConvertShippingTimeWindowEx(sshipmentTimeSpans);
            //Validate
            if (shipmentTimeSpans == null || shipmentTimeSpans.Count == 0)
                return null;

            var query = shipmentTimeSpans.Where(
                d => d.AllowOrderType.Contains(orderType) && d.AllowAddressType.Contains(addressType));

            query = !_zipPostalCodeService.ValidateIsContain(zipPostalCode) ? query.Where(d => d.Id != 3) : query;

            return query.ToList();
        }

        //获取weeks注意事项
        //如果电商订单 
        //商业地址：每天早上六点之前下单可以选择当天第一时间段运送，否则只能次日第一时间段运送
        //住宅地址：如果当天早上六点之前下单，可以选择第一时段和第二时段
        //如果物流订单 
        //只能选择第二天的第一时间段发货
        public IList<Day> GetValidateDays(IList<ShippingTimeWindowEx> timeSpans, bool isShippingWeekends, DateTime dateTimeNow, int dayNums)
        {
            //Validate
            if (timeSpans == null || timeSpans.Count == 0 || dayNums < 3)
                return null;

            List<Day> days = new List<Day>();
            DateTime dateTimeCNT = new DateTime(dateTimeNow.Year, dateTimeNow.Month, dateTimeNow.Day);
            var timeSpanVmodel = timeSpans;
            if (IsWeekwend(dateTimeNow) || IsVacation(dateTimeNow))
            {
                //今天不是有效时间
                AddDays(dateTimeCNT.AddDays(1), timeSpanVmodel, isShippingWeekends, dayNums, ref days);
            }
            else
            {
                //排除今天不是节假日 不是周六日
                if (dateTimeNow < ConvertTimeSpanToDateTime(dateTimeNow, timeSpans.LastOrDefault().SameDayCutoff))
                {
                    //如果现在的时间大于最后一个时间段允许的时间那么就证明今天有效
                    var day = new Day() { Num = 1, Time = dateTimeCNT, ShipmentTimeSpans = new List<ShippingTimeWindowEx>() };
                    foreach (var shipmentSpan in timeSpanVmodel)
                    {
                        if (dateTimeNow < ConvertTimeSpanToDateTime(dateTimeNow, shipmentSpan.SameDayCutoff))
                        {
                            day.ShipmentTimeSpans.Add(shipmentSpan);
                        }
                    }
                    day.ShipmentTimeNum = day.ShipmentTimeSpans.Count;
                    days.Add(day);
                }
                AddDays(dateTimeCNT.AddDays(1), timeSpanVmodel, isShippingWeekends, dayNums - days.Count, ref days);
            }
            return days;
        }
        private bool IsWeekwend(DateTime day)
        {
            if (day.DayOfWeek == DayOfWeek.Sunday || day.DayOfWeek == DayOfWeek.Saturday)
                return true;
            else
                return false;
        }

        private bool IsVacation(DateTime day)
        {
            return _holidayService.IsHoliday(day);
        }

        private DateTime ConvertTimeSpanToDateTime(DateTime date, int cutoff)
        {
            return new DateTime(date.Year, date.Month, date.Day).AddMinutes(cutoff);
        }

        private void AddDays(DateTime startTime, IList<ShippingTimeWindowEx> timeSpans, bool IsShippingWeekends, int dayNums, ref List<Day> days)
        {
            DateTime datetimeTemp = startTime;
            int num = days.Count;
            int counter = 1;
            for (int i = 1; i <= dayNums; i++)
            {
                var date = datetimeTemp.AddDays(i - 1);
                if (IsWeekwend(date) || IsVacation(date))
                    continue;
                else
                {
                    //有效时间
                    var day = new Day() { Num = counter, Time = date, ShipmentTimeSpans = timeSpans };
                    day.ShipmentTimeNum = day.ShipmentTimeSpans.Count;
                    days.Add(day);
                    counter++;
                }
            }
        }

    }
}
